#include "MetaGenerator.h"
#include "HeadFile.h"
#include "Token.h"

#include <cassert>

CMetaGenerator::CMetaGenerator(CHeadFile *InContext)
{
    Context = InContext;
}

void CMetaGenerator::Generate()
{
    //skip '('
    {
        auto Token = Context->GetCurrentToken();
        if(Token->Type == ETokenType::LeftParentheses)
        {
            Context->GotoNextToken();
        }
        else
        {
            Context->RaiseError(Token, U"expect '('");
        }
    }

    auto Token = Context->GetCurrentToken();
    while(Token->Type!= ETokenType::RightParentheses)
    {   
        Token = Context->GetCurrentToken();
        //read key
        if(Token->Type!= ETokenType::Identifier)
        {
            Context->RaiseError(Token, U"expect identifier");
        }

        auto Key = std::get<C32String>(Token->LiteralValue.value()).ToUtf8();
        Result[Key] = std::nullopt;
        Context->GotoNextToken();

        {
            auto EqualToken = Context->GetCurrentToken();
            if(EqualToken->Type == ETokenType::Assign )
            {
                Context->GotoNextToken();

                auto ValueToken = Context->GetCurrentToken();

                MetaValue Value;
                switch(ValueToken->Type)
                {
                    case ETokenType::LiteralNumber:
                    {
                        std::variant<std::u8string, std::vector<std::u8string>,double> Number =(double) std::get<double>(ValueToken->LiteralValue.value());
                        Value = Number; 
                        Context->GotoNextToken();
                        break;
                    }

                    case ETokenType::LiteralString:
                    {
                        std::variant<std::u8string, std::vector<std::u8string>,double> String = std::get<C32String>(ValueToken->LiteralValue.value()).ToUtf8();
                        Value = String; 
                        Context->GotoNextToken();
                        break;
                    }

                    case ETokenType::LeftBracket:
                    {
                        //skip '['
                        Context->GotoNextToken();

                        std::vector<std::u8string> StringArray;

                        while(true)
                        {
                            auto ArrayToken = Context->GetCurrentToken();
                            if(ArrayToken->Type == ETokenType::LiteralString)
                            {
                                StringArray.push_back(std::get<C32String>(ArrayToken->LiteralValue.value()).ToUtf8());
                                Context->GotoNextToken();
                            }
                            else if(ArrayToken->Type == ETokenType::Comma)
                            {
                                Context->GotoNextToken();
                                continue;
                            }
                            else if(ArrayToken->Type == ETokenType::RightBracket)
                            {
                                Context->GotoNextToken(); //skip ']'
                                break;
                            }
                            else
                            {
                                Context->RaiseError(ArrayToken, U"expect string");
                            }
                        }
                        
                        Value = StringArray;
                        break;
                    }

                    default:
                    {
                        //raise error 
                        Context->RaiseError(ValueToken, U"expect a value with type string or string list, string must be quoted by '\"'  ");
                        return;
                    }

                }

                Result[Key] = Value;
                auto CommaToken = Context->GetCurrentToken();
                if(CommaToken->Type == ETokenType::Comma)
                {
                    Context->GotoNextToken();
                    Token = Context->GetCurrentToken();
                    continue;
                }
                else if(CommaToken->Type == ETokenType::RightParentheses)
                {
                    break;
                }
                else
                {
                    Context->RaiseError(CommaToken, U"expect ',' or ')'");
                }

            }
            else if (EqualToken->Type == ETokenType::Comma)
            {
                Context->GotoNextToken();
                continue;
            }
            else if(EqualToken->Type == ETokenType::RightParentheses)
            {
                break;
            }
            else
            {
                Context->RaiseError(EqualToken, U"expect a '=' after meta tag ");
            }
        }   


    }

    //skip ')'
    {
        auto Token = Context->GetCurrentToken();
        if(Token->Type == ETokenType::RightParentheses)
        {
            Context->GotoNextToken();
        }
        else
        {
            Context->RaiseError(Token, U"expect ')'");
        }
    }



}
